From e4643b52b18f0ff2e091de1226dd052e82ae7a63 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 27 Sep 2016 14:39:08 +0300 Subject: [PATCH] Don't panic while streaming compiler output --- src/cargo/ops/cargo_rustc/custom_build.rs | 4 ++-- src/cargo/ops/cargo_rustc/mod.rs | 14 ++++++++----- src/cargo/util/errors.rs | 9 ++++---- src/cargo/util/process_builder.rs | 25 +++++++++++++++-------- 4 files changed, 33 insertions(+), 19 deletions(-) diff --git a/src/cargo/ops/cargo_rustc/custom_build.rs b/src/cargo/ops/cargo_rustc/custom_build.rs index 883582489..5a15e85a8 100644 --- a/src/cargo/ops/cargo_rustc/custom_build.rs +++ b/src/cargo/ops/cargo_rustc/custom_build.rs @@ -206,8 +206,8 @@ fn build_work<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>) state.running(&p); let cmd = p.into_process_builder(); let output = try!(cmd.exec_with_streaming( - &mut |out_line| state.stdout(out_line), - &mut |err_line| state.stderr(err_line), + &mut |out_line| { state.stdout(out_line); Ok(()) }, + &mut |err_line| { state.stderr(err_line); Ok(()) }, ).map_err(|mut e| { e.desc = format!("failed to run custom build command for `{}`\n{}", pkg_name, e.desc); diff --git a/src/cargo/ops/cargo_rustc/mod.rs b/src/cargo/ops/cargo_rustc/mod.rs index dac09a7ea..7d423dd8d 100644 --- a/src/cargo/ops/cargo_rustc/mod.rs +++ b/src/cargo/ops/cargo_rustc/mod.rs @@ -280,11 +280,15 @@ fn rustc(cx: &mut Context, unit: &Unit) -> CargoResult { message: json::Json, } process_builder.exec_with_streaming( - &mut |line| assert!(line.is_empty()), + &mut |line| if !line.is_empty() { + Err(internal(&format!("compiler stdout is not empty: `{}`", line))) + } else { + Ok(()) + }, &mut |line| { - let rustc_message = json::Json::from_str(line).unwrap_or_else(|_| { - panic!("Compiler produced invalid json: `{}`", line) - }); + let rustc_message = try!(json::Json::from_str(line).map_err(|_| { + internal(&format!("compiler produced invalid json: `{}`", line)) + })); let message = Message { reason: "rustc-message", @@ -294,7 +298,7 @@ fn rustc(cx: &mut Context, unit: &Unit) -> CargoResult { }; let encoded = json::encode(&message).unwrap(); println!("{}", encoded); - + Ok(()) }, ).map(|_| ()) } else { diff --git a/src/cargo/util/errors.rs b/src/cargo/util/errors.rs index 8b41dd3e6..39e22cbe5 100644 --- a/src/cargo/util/errors.rs +++ b/src/cargo/util/errors.rs @@ -110,13 +110,13 @@ pub struct ProcessError { pub desc: String, pub exit: Option, pub output: Option, - cause: Option, + cause: Option>, } impl Error for ProcessError { fn description(&self) -> &str { &self.desc } fn cause(&self) -> Option<&Error> { - self.cause.as_ref().map(|s| s as &Error) + self.cause.as_ref().map(|e| &**e as &Error) } } @@ -375,9 +375,10 @@ impl CargoError for str::ParseBoolError {} // Construction helpers pub fn process_error(msg: &str, - cause: Option, + cause: Option>, status: Option<&ExitStatus>, - output: Option<&Output>) -> ProcessError { + output: Option<&Output>) -> ProcessError +{ let exit = match status { Some(s) => status_to_string(s), None => "never executed".to_string(), diff --git a/src/cargo/util/process_builder.rs b/src/cargo/util/process_builder.rs index 856e337e2..c0d88d2ae 100644 --- a/src/cargo/util/process_builder.rs +++ b/src/cargo/util/process_builder.rs @@ -5,7 +5,7 @@ use std::fmt; use std::path::Path; use std::process::{Command, Stdio, Output}; -use util::{ProcessError, process_error, read2}; +use util::{CargoResult, ProcessError, process_error, read2}; use util::shell_escape::escape; #[derive(Clone, PartialEq, Debug)] @@ -77,7 +77,7 @@ impl ProcessBuilder { let exit = try!(command.status().map_err(|e| { process_error(&format!("could not execute process `{}`", self.debug_string()), - Some(e), None, None) + Some(Box::new(e)), None, None) })); if exit.success() { @@ -94,8 +94,8 @@ impl ProcessBuilder { let output = try!(command.output().map_err(|e| { process_error(&format!("could not execute process `{}`", - self.debug_string()), - Some(e), None, None) + self.debug_string()), + Some(Box::new(e)), None, None) })); if output.status.success() { @@ -108,8 +108,8 @@ impl ProcessBuilder { } pub fn exec_with_streaming(&self, - on_stdout_line: &mut FnMut(&str), - on_stderr_line: &mut FnMut(&str)) + on_stdout_line: &mut FnMut(&str) -> CargoResult<()>, + on_stderr_line: &mut FnMut(&str) -> CargoResult<()>) -> Result { let mut stdout = Vec::new(); let mut stderr = Vec::new(); @@ -119,6 +119,7 @@ impl ProcessBuilder { .stderr(Stdio::piped()) .stdin(Stdio::null()); + let mut callback_error = None; let status = try!((|| { let mut child = try!(cmd.spawn()); let out = child.stdout.take().unwrap(); @@ -137,10 +138,14 @@ impl ProcessBuilder { let start = dst.len(); dst.extend(data); for line in String::from_utf8_lossy(&dst[start..]).lines() { - if is_out { + if callback_error.is_some() { break } + let callback_result = if is_out { on_stdout_line(line) } else { on_stderr_line(line) + }; + if let Err(e) = callback_result { + callback_error = Some(e); } } })); @@ -148,7 +153,7 @@ impl ProcessBuilder { })().map_err(|e| { process_error(&format!("could not execute process `{}`", self.debug_string()), - Some(e), None, None) + Some(Box::new(e)), None, None) })); let output = Output { stdout: stdout, @@ -159,6 +164,10 @@ impl ProcessBuilder { Err(process_error(&format!("process didn't exit successfully: `{}`", self.debug_string()), None, Some(&output.status), Some(&output))) + } else if let Some(e) = callback_error { + Err(process_error(&format!("failed to parse process output: `{}`", + self.debug_string()), + Some(Box::new(e)), Some(&output.status), Some(&output))) } else { Ok(output) } -- 2.30.2